﻿using System;

namespace CcMath
{
    public class Point3D
    {
        private float mX, mY, mZ, mCylR, mSphR;//mm
        private float mPhi, mSita;//deg
        private bool autoRefresh = true;
        //是否马上刷新数据的标志，用于构造函数中设置完坐标值后才进行坐标更新，以降低运算量
        public float X
        {
            get { return mX; }
            set
            {
                mX = value;
                if (autoRefresh)
                {
                    CalculateCylinder();
                    CalculateSphere();
                }

            }
        }
        public float Y
        {
            get { return mY; }
            set
            {
                mY = value;
                if (autoRefresh)
                {
                    CalculateCylinder();
                    CalculateSphere();
                }
            }
        }
        public float Z
        {
            get { return mZ; }
            set
            {
                mZ = value;
                if (autoRefresh)
                {
                    CalculateCylinder();
                    CalculateSphere();
                }
            }
        }

        public float PhiOfCyl
        {
            get { return mPhi; }
            set
            {
                mPhi = value;
                if (autoRefresh)
                {
                    CylToXyz();
                    CalculateSphere();
                }
            }
        }
        public float RofCyl
        {
            get { return mCylR; }
            set
            {
                mCylR = value;
                if (autoRefresh)
                {
                    CylToXyz();
                    CalculateSphere();
                }
            }
        }
        public float ZofCyl
        {
            get { return mZ; }
            set
            {
                mZ = value;
                if (autoRefresh)
                {
                    CylToXyz();
                    CalculateSphere();
                }
            }
        }
        public float RofSph
        {
            get { return mSphR; }
            set
            {
                mSphR = value;
                if (autoRefresh)
                {
                    SphToCart();
                    CalculateSphere();
                }
            }
        }

        public float PhiofSph
        {
            get { return mPhi; }
            set
            {
                mPhi = value;
                if (autoRefresh)
                {
                    SphToCart();
                    CalculateSphere();
                }
            }
        }

        public float Sita
        {
            get { return mSita; }
            set
            {
                mSita = value;
                if (autoRefresh)
                {
                    SphToCart();
                    CalculateSphere();
                }
            }
        }
        /// <summary>
        /// 向量模值
        /// </summary>
        public double Magtitude
        {
            get
            {
                return mSphR;
            }
        }
        public Point3D(float xOrR, float yOrPhi, float zOrSita, ECoordinates coordinate = ECoordinates.Spherical)
        {
            autoRefresh = false;
            switch (coordinate)
            {
                case ECoordinates.Cartesian:
                    X = xOrR;
                    Y = yOrPhi;
                    autoRefresh = true;
                    Z = zOrSita;
                    break;
                case ECoordinates.Cyclinder:
                    RofCyl = xOrR;
                    PhiOfCyl = yOrPhi;
                    autoRefresh = true;
                    ZofCyl = zOrSita;
                    break;
                case ECoordinates.Spherical:
                    RofSph = xOrR;
                    PhiofSph = yOrPhi;
                    autoRefresh = true;
                    Sita = zOrSita;
                    break;
                default:
                    break;
            }

        }
        public Point3D(double xOrR, double yOrPhi, double zOrSita, ECoordinates coordinate = ECoordinates.Spherical)
        {
            autoRefresh = false;
            switch (coordinate)
            {
                case ECoordinates.Cartesian:
                    X = (float)xOrR;
                    Y = (float)yOrPhi;
                    autoRefresh = true;
                    Z = (float)zOrSita;
                    break;
                case ECoordinates.Cyclinder:
                    RofCyl = (float)xOrR;
                    PhiOfCyl = (float)yOrPhi;
                    autoRefresh = true;
                    ZofCyl = (float)zOrSita;
                    break;
                case ECoordinates.Spherical:
                    RofSph = (float)xOrR;
                    PhiofSph = (float)yOrPhi;
                    autoRefresh = true;
                    Sita = (float)zOrSita;
                    break;
                default:
                    break;
            }

        }
        /// <summary>
        /// 以直角坐标为基础计算球坐标
        /// </summary>
        private void CalculateSphere()
        {
            mSphR = (float)Math.Sqrt(mX * mX + mY * mY + mZ * mZ);
            mPhi = (float)(Math.Atan2(mY, mX)).ToDeg();
            if (mSphR == 0) mSita = 0;
            else
            {
                double v = mZ / mSphR;
                mSita = (float)(Math.Acos(v)).ToDeg();
            }

        }
        /// <summary>
        /// 以直角坐标为基础计算柱坐标
        /// </summary>
        private void CalculateCylinder()
        {
            mPhi = (float)(Math.Atan2(mY, mX)).ToDeg();
            mCylR = (float)Math.Sqrt(mX * mX + mY * mY);
        }
        private void CylToXyz()
        {
            mX = (float)(mCylR * Math.Cos(mPhi.ToRad()));
            mY = (float)(mCylR * Math.Sin(mPhi.ToRad()));
        }
        private void SphToCart()
        {
            mX = (float)(mSphR * Math.Sin(mSita.ToRad()) * Math.Cos(mPhi.ToRad()));
            mY = (float)(mSphR * Math.Sin(mSita.ToRad()) * Math.Sin(mPhi.ToRad()));
            mZ = (float)(mSphR * Math.Cos(mSita.ToRad()));
        }

    }
}
